﻿using System;
using System.Collections.Generic;
using System.Linq;
using Sustainalytics.Entities;
using System.Security.Claims;

namespace Sustainalytics.Claims
{
    public class ClaimsChecker : IClaimsChecker, IDisposable
    {
        private IOperationClaimsRetriever _operationClaimsRetriever;
        bool _disposed = false;
        public IEnumerable<ResourceMap> GetUIResources(ClaimsPrincipal claimsPrincipal)
        {
            return _operationClaimsRetriever.GetUIResources(claimsPrincipal.Claims.ToList());
        }

        public bool Validate(ClaimsPrincipal claimsPrincipal, string resource, string verb,
            List<ResourceParameters> parameters)
        {
            if (claimsPrincipal == null)
                return false;

            var userClaims = claimsPrincipal.Claims.ToList();

            var resourceClaims = _operationClaimsRetriever.GetClaims(new Resource {Name = resource}, verb, parameters).ToList();

            if (!resourceClaims.Any())
                return false;

            var annonymousUserClaims =
                userClaims.Select(x => new {x.Value, x.Type}).ToList().OrderByDescending(x => x.Type);

            var annonymousResourceClaims =
                resourceClaims.Select(x => new {x.Value, x.Type}).ToList().OrderByDescending(x => x.Type).Distinct();

            var intersect = annonymousUserClaims.Intersect(annonymousResourceClaims);

            var checker = annonymousResourceClaims.SequenceEqual(intersect);

            return checker;
        }

        public ClaimsChecker()
            : this(new OperationClaimsRetriever())
        {
        }

        public ClaimsChecker(IOperationClaimsRetriever operationsClaimsRetriever)
        {
            this._operationClaimsRetriever = operationsClaimsRetriever;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_disposed)
                return;

            if (disposing)
            {
                _operationClaimsRetriever = null;
            }

            _disposed = true;
        }

        ~ClaimsChecker()
        {
            Dispose(false);
        }
    }
}
